home *** CD-ROM | disk | FTP | other *** search
- /* menu.c */
-
- #include<stdio.h>
- #include<bios.h>
- #include<string.h>
- #include"PcMag.h"
-
- /* screen colors:
- * NORMAL_VID value for ordinary characters,
- * HIGHLITE for reverse
- */
-
- #define NORMAL_VID 0x1700 /* white text, blue field */
- #define HIGHLITE_VID 0x7000 /* black text, white field */
-
- /* Ascii key definitions */
-
- #define ENTER 13
- #define SPACE 32
- #define ESC 27
-
- /* Scan key redefinitions */
-
- #define RIGHT_ARROW 77+'z'
- #define LEFT_ARROW 75+'z'
-
- /* limitations: */
-
- #define MAXMENUITEMS 25 /* number of menu items */
- #define NAME_ROW 2 /* row number of item name */
- #define NAME_COL 1 /* column number for name */
- #define DESCRIPTION_ROW 3 /* description row number */
- #define DESCRIPTION_COL 2 /* description column */
-
- /* macros to make the code more readable, don't touch these */
-
- #define SCREEN_SIZE 2000 /* screen size @ 2000 words */
- #define ring_bell() putch(7) /* bell-ringing macro */
- #define VIDEO_INT 0x10 /* Bios video interrupt */
- #define SET_CURSOR_SIZE 0x01 /* Int 10 function 1 */
- #define GET_CURSOR_POS 0x02 /* Int 10 function 2 */
- #define READ_CURSOR 0x03 /* Int 10 function 3 */
- #define GET_VID_MODE 0x0f /* Int 10 function F */
- #define MONO_MODE 7 /* monochrome video mode # */
- #define MONO_SCREEN 0xb0000000 /* address of mono screen */
- #define COLOR_SCREEN 0xb8000000 /* address of color screen */
- #define CURSOR_SAVE 0 /* macro for cursor save */
- #define CURSOR_RESTORE 1 /* macro for cursor store */
-
- /* global objects: */
-
- int far *screen; /* pointer to screen buffer */
- int old_screen[SCREEN_SIZE]; /* store old screen here */
-
- /* list of function declarations for cue_function */
-
- int addf(), subf(), mulf(), divf(), exitf();
-
- /* array of structures with names, descriptions and function pointers */
-
- struct _cue
- {
- char *cue_name; /* name to be displayed */
- char *cue_description; /* description */
- int (*cue_function)(); /* function to be called */
- }
- cue[MAXMENUITEMS] =
- {
- /* --1234567890--------1234567890123456789012-----for alignment */
-
- " Add ", "Explain addition ", addf,
- " Subtract ", "Discuss subtraction ", subf,
- " Multiply ", "Portray multiplication", mulf,
- " Divide ", "Characterize division ", divf,
- " Exit ", "Exit to system ", exitf,
-
- /* you can add more items here in the same fashion -
- * up to MAXMENUITEMS total
- */
- NULL,NULL,NULL
- };
-
-
- /* functions */
-
- /* cls()
- * clears the screen by writing blanks to screen buffer
- */
- cls()
- {
- int pos=0;
-
- while(pos < SCREEN_SIZE) /* for each word in screen */
- *(screen + pos++) = NORMAL_VID; /* set it to NORMAL_VID */
- }
-
- /* print()
- * prints a null-terminated string at row,col with attributes
- * returns next available column
- */
- print(str, row, col, att)
- char *str;
- int row, col, att;
- {
- while(*str)
- *(screen+row*80+col++) = att + *str++;
- return (col);
- }
-
- /* four test functions */
- addf()
- {
- cls();
- print("In Add, press a key for menu",2,1,HIGHLITE_VID);
- getch();
- }
-
- subf()
- {
- cls();
- print("In Subtract, press a key for menu",2,1,HIGHLITE_VID);
- getch();
- }
-
- mulf()
- {
- cls();
- print("In Multiply, press a key for menu",2,1,HIGHLITE_VID);
- getch();
- }
-
- divf()
- {
- cls();
- print("In Divide, press a key for menu",2,1,HIGHLITE_VID);
- getch();
- }
-
- exitf()
- {
- int i;
-
- for( i = 0; i < SCREEN_SIZE; i++) /* restore original screen */
- *(screen+i) = old_screen[i];
-
- cursor(CURSOR_RESTORE); /* reset cursor size/posit.*/
- }
-
-
- /* Run()
- * runs the appropriate test function at cue[itemnumber].cue_function.
- * This could be modified to use spawn() to run other programs.
- */
- Run(itemnumber)
- int itemnumber;
- {
- return (cue[itemnumber].cue_function)();
- }
-
- /* cursor() * cursor operations: saves the current cursor size and position in
- * the statics, or restores the cursor size and position previously
- * saved.
- */
- cursor(op)
- {
- union REGS r;
- static int oldcurrow,oldcurcol,oldcurstart,oldcurend;
-
- if(op) /* restore cursor */
- {
- r.h.ah = SET_CURSOR_POS; /* cursor position function */
- r.h.dh = oldcurrow; /* set the row */
- r.h.dl = oldcurcol; /* set the column */
- r.h.bh = 0; /* for video page 0 */
- int86(VIDEO_INT,&r,&r); /* call the bios */
-
- r.h.ah = SET_CURSOR_SIZE; /* cursor size function */
- r.h.ch = oldcurstart; /* set the start */
- r.h.cl = oldcurend; /* set the end */
- r.h.bh = 0; /* for video page 0 */
- int86(VIDEO_INT,&r,&r); /* call the bios */
- }
- else /* save the cursor */
- {
- r.h.ah = READ_CURSOR; /* cursor read function */
- r.h.bh = 0; /* page 0 */
- int86(VIDEO_INT,&r,&r); /* call the bios */
- oldcurrow = r.h.dh; /* save the cursor row */
- oldcurcol = r.h.dl = 0; /* save the cursor column */
- oldcurstart = r.h.ch; /* save the cursor start */
- oldcurend = r.h.cl; /* save the cursor end */
- r.h.ah = SET_CURSOR_SIZE; /* cursor size function */
- r.h.ch = 0x20; /* set bit 5 to hide cursor */
- int86(VIDEO_INT,&r,&r); /* call the bios */
- }
- }
-
- /* initialize()
- * initializes the initials array, sets number of choices found, and
- * saves the screen buffer in the old_screen array
- */
- initialize(choices,initials)
- int *choices;
- char *initials;
- {
- int i;
- get_screen_mode(); /* set screen pointer */
-
- /* initialize the initials */
- for( i = 0; cue[i].cue_name && i < MAXMENUITEMS; i++)
- initials[i] = tolower(cue[i].cue_name[1]);
- initials[i] = NULL;
- *choices = i;
- /* save old screen */
- for( i = 0; i < SCREEN_SIZE; i++)
- old_screen[i] = *(screen+i);
- }
-
- /* get_screen_mode()
- * returns the current screen mode in AL, and sets the screen pointer
- * to the appropriate video buffer address.
- */
- get_screen_mode()
- {
- union REGS r;
-
- r.h.ah = GET_VID_MODE; /* get video mode function */
- int86(VIDEO_INT,&r,&r); /* call the bios */
- /* set screen pointer */
- screen = (int far *)((r.h.al == MONO_MODE) ? MONO_SCREEN : COLOR_SCREEN);
- }
-
- /* menu()
- * main menu creation function, callable from anywhere in a program.
- * Performs the following tasks:
- * 1. saves the current screen and cursor
- * 2. clears the screen
- * 3. loops until the exit function is called through the following:
- * 1. prints the menu items (highlights current selection)
- * 2. prints the description of the highlighted selection
- * 3. gets a key from the user (adjusts for non-ascii keys)
- * 4. takes the appropriate actions for <ENTER>, <SPACE>,
- * <LEFT-ARROW>, <RIGHT-ARROW>, <ESC>, or the first
- * letter of the menu item.
- * Assumes last item is exit item and returns when that is executed.
- */
- menu()
- {
- static int mark = 0;
- int col, i, key, choices;
- char *match, initials[MAXMENUITEMS];
-
- initialize(&choices,initials); /* initialize & save screen */
-
- cursor(CURSOR_SAVE); /* save the cursor */
- cls(); /* clear the screen */
-
- while(TRUE) /* main loop */
- {
- col = NAME_COL;
-
- /* print the names and highlight the current selection */
-
- for( i = 0; i < choices; i++)
- col = print(cue[i].cue_name, NAME_ROW, col,
- (mark == i) ? HIGHLITE_VID : NORMAL_VID);
- /* print description */
-
- print(cue[mark].cue_description, DESCRIPTION_ROW, DESCRIPTION_COL, NORMAL_VID);
-
- if(!(key = tolower(getch()))) /* get key, and lowercase */
- key = (getch() + 'z'); /* Not Ascii? get scan code */
-
- switch(key) /* which key was pressed? */
- {
- case ENTER: /* if ENTER */
- Run(mark); /* run function at mark */
- break;
-
- case RIGHT_ARROW: /* if RIGHT_ARROW/SPACE bar */
- case SPACE:
- mark = ((mark+1) % choices); /* move to next choice */
- break;
-
- case LEFT_ARROW: /* if LEFT_ARROW */
- /* move to previous choice */
- mark = ((mark+choices-1) % choices);
- break;
-
- case ESC: /* if ESC */
- return Run(choices-1); /* select last choice (exit)*/
- break;
-
- default: /* if initials match */
- if(match = strchr(initials,key))
- {
- mark = (match-initials);
- Run(match-initials);
- }
- else
- ring_bell(); /* bad choice, ring the bell*/
- break;
- }
- }
- }
-
- main() /* main program */
- {
- menu(); /* called as needed */
- }
-
- /* End of Menu.c */